package org.mybatis.generator.codegen.spring.jdbc;

import static org.mybatis.generator.internal.util.StringUtility.stringHasValue;
import static org.mybatis.generator.internal.util.messages.Messages.getString;

import java.util.ArrayList;
import java.util.List;

import org.mybatis.generator.api.CommentGenerator;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.codegen.AbstractJavaClientGenerator;
import org.mybatis.generator.codegen.AbstractXmlGenerator;
import org.mybatis.generator.codegen.spring.jdbc.repository.AbstractRepGenerator;
import org.mybatis.generator.codegen.spring.jdbc.repository.elements.DeleteByPrimaryKeyMethodGenerator;
import org.mybatis.generator.codegen.spring.jdbc.repository.elements.InsertMethodGenerator;
import org.mybatis.generator.codegen.spring.jdbc.repository.elements.SelectByPrimaryKeyMethodGenerator;
import org.mybatis.generator.codegen.spring.jdbc.repository.elements.UpdateByPrimaryKeySelectiveMethodGenerator;
import org.mybatis.generator.config.PropertyRegistry;

public class SpringJdbcClientGenerator extends AbstractJavaClientGenerator {
	public SpringJdbcClientGenerator() {
		super(false);
	}

	@Override
	public List<CompilationUnit> getCompilationUnits() {
		progressCallback.startTask(getString("Progress.17", //$NON-NLS-1$
				introspectedTable.getFullyQualifiedTable().toString()));
		CommentGenerator commentGenerator = context.getCommentGenerator();
		
		FullyQualifiedJavaType dataSource = new FullyQualifiedJavaType("javax.sql.DataSource");
		FullyQualifiedJavaType jdbcTemplate = new FullyQualifiedJavaType(
				"org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate");
		FullyQualifiedJavaType simpleJdbcInsert = new FullyQualifiedJavaType(
				"org.springframework.jdbc.core.simple.SimpleJdbcInsert");
	
		// 设置class 名
		FullyQualifiedJavaType type = new FullyQualifiedJavaType(
				introspectedTable.getDAOImplementationType());
		TopLevelClass topLevelClass = new TopLevelClass(type);
		topLevelClass.setVisibility(JavaVisibility.PUBLIC);
		//topLevelClass.addAnnotation("@Repository");
//		topLevelClass.addImportedType(new FullyQualifiedJavaType(
//				"org.springframework.stereotype.Repository"));
		commentGenerator.addJavaFileComment(topLevelClass);
		
	
		topLevelClass.addImportedType(dataSource);
		topLevelClass.addImportedType(jdbcTemplate);
		topLevelClass.addImportedType(simpleJdbcInsert);
		
		String rootInterface = introspectedTable
				.getTableConfigurationProperty(PropertyRegistry.ANY_ROOT_INTERFACE);
		if (!stringHasValue(rootInterface)) {
			rootInterface = context.getJavaClientGeneratorConfiguration().getProperty(
					PropertyRegistry.ANY_ROOT_INTERFACE);
		}

		if (stringHasValue(rootInterface)) {
			FullyQualifiedJavaType fqjt = new FullyQualifiedJavaType(rootInterface);
			topLevelClass.addSuperInterface(fqjt);
			topLevelClass.addImportedType(fqjt);
		}
	
		Field field = new Field("jdbcTemplate", jdbcTemplate);
		field.setVisibility(JavaVisibility.PROTECTED);
		topLevelClass.addField(field);
		Field fieldsimpleJdbcInsert = new Field("simpleJdbcInsert", simpleJdbcInsert);
		fieldsimpleJdbcInsert.setVisibility(JavaVisibility.PROTECTED);
		topLevelClass.addField(fieldsimpleJdbcInsert);
		// add default constructor
		Method method = new Method();
		method.setVisibility(JavaVisibility.PUBLIC);
		method.setConstructor(true);
		method.setName(type.getShortName());
		//method.addAnnotation("@Autowired");
//		topLevelClass.addImportedType(new FullyQualifiedJavaType(
//				"org.springframework.beans.factory.annotation.Autowired"));
		method.addParameter(new Parameter(dataSource, "dataSource"));
		method.addBodyLine("this.jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);"); //$NON-NLS-1$
		method.addBodyLine("this.simpleJdbcInsert = new SimpleJdbcInsert(dataSource).withTableName(\"" + introspectedTable.getFullyQualifiedTable().getIntrospectedTableName() + "\");"); //$NON-NLS-1$

		commentGenerator.addGeneralMethodComment(method, introspectedTable);
		topLevelClass.addMethod(method);
		
		topLevelClass.addMethod(this.getGetter(fieldsimpleJdbcInsert));
		topLevelClass.addMethod(this.getGetter(field));
	
		addInsertMethod(topLevelClass);
		addSelectByPrimaryKeyMethod(topLevelClass);
		addUpdateByPrimaryKeyMethod(topLevelClass);
		addDeleteByPrimaryKeyMethod(topLevelClass);

		List<CompilationUnit> answer = new ArrayList<CompilationUnit>();
		if (context.getPlugins().clientGenerated(null, topLevelClass, introspectedTable)) {
			answer.add(topLevelClass);
		}

		List<CompilationUnit> extraCompilationUnits = getExtraCompilationUnits();
		if (extraCompilationUnits != null) {
			answer.addAll(extraCompilationUnits);
		}

		return answer;
	}

	protected void addDeleteByPrimaryKeyMethod(TopLevelClass topLevelClass) {
		if (introspectedTable.getRules().generateDeleteByPrimaryKey()) {
			AbstractRepGenerator methodGenerator = new DeleteByPrimaryKeyMethodGenerator();
			initializeAndExecuteGenerator(methodGenerator, topLevelClass);
		}
	}

	protected void addInsertMethod(TopLevelClass topLevelClass) {
		if (introspectedTable.getRules().generateInsert()) {
			AbstractRepGenerator methodGenerator = new InsertMethodGenerator(false);
			initializeAndExecuteGenerator(methodGenerator, topLevelClass);
		}
	}

	protected void addSelectByPrimaryKeyMethod(TopLevelClass topLevelClass) {
		if (introspectedTable.getRules().generateSelectByPrimaryKey()) {
			AbstractRepGenerator methodGenerator = new SelectByPrimaryKeyMethodGenerator();
			initializeAndExecuteGenerator(methodGenerator, topLevelClass);
		}
	}

	protected void addUpdateByPrimaryKeyMethod(TopLevelClass topLevelClass) {
		if (introspectedTable.getRules().generateUpdateByPrimaryKeySelective()) {
			AbstractRepGenerator methodGenerator = new UpdateByPrimaryKeySelectiveMethodGenerator();
			initializeAndExecuteGenerator(methodGenerator, topLevelClass);
		}
	}

	protected void initializeAndExecuteGenerator(AbstractRepGenerator methodGenerator,
			TopLevelClass topLevelClass) {
		methodGenerator.setContext(context);
		methodGenerator.setIntrospectedTable(introspectedTable);
		methodGenerator.setProgressCallback(progressCallback);
		methodGenerator.setWarnings(warnings);
		methodGenerator.addImplementationElements(topLevelClass);
	}

	public List<CompilationUnit> getExtraCompilationUnits() {
		return null;
	}

	@Override
	public AbstractXmlGenerator getMatchedXMLGenerator() {
		return null;
	}

}
